home *** CD-ROM | disk | FTP | other *** search
- {*******************************************************}
- { }
- { Turbo Pascal Version 6.0 }
- { Optional FormLine Unit }
- { for use with Turbo Vision }
- { }
- { Copyright (c) 1991 J. John Sprenger }
- { }
- {*******************************************************}
-
- unit FormLine;
-
- {$O+,F+,S+}
-
- interface
-
- uses
-
- {Turbo Pascal Run-Time Library Units}
-
- Crt,
-
- {Turbo Vision Standard Units}
-
- Objects, Drivers, Views, Dialogs, App,
-
- {Turbo Vision Accessory Units}
-
- StdDlg, MsgBox;
-
- const
-
- { flError, flCharOk and flFormatOK are constants used }
- { by tFormatLine.CheckPicture. flError is returned }
- { when an error is found. flCharOk when an character }
- { is found to be appropriate. And flFormatOk when the }
- { entire input string is found acceptable. }
-
- flError = $0000;
- flCharOK = $0001;
- flFormatOK = $0002;
-
- { flCharError is passed to tFormatLine.ReportError }
- { when a character does not fit the proper form. }
- { flFormatError is used when the format is not }
- { satisfied even though input so far is acceptable. }
-
- flCharError = 1;
- flFormatError = 2;
-
- { CommandSet represents the characters used in Format }
- { Line Pictures. These match those used by Paradox. }
-
- CommandSet = ['[','{','?','&','@','!','#','{',',',']',
- '}','*'];
-
- type
-
- { tFormatLine }
-
- { tFormatLine is the improved tInputLine object which }
- { accepts Paradox-form Picture strings to ensure that }
- { data will be entered in an acceptable form. }
-
- pFormatLine = ^tFormatLine;
- tFormatLine = object( tInputLine)
- Picture : string;
- constructor Init(var Bounds : tRect; AMaxLen
- : integer; Pic : string);
- function Valid(command : word) : boolean; virtual;
- procedure HandleEvent(var Event : tEvent); virtual;
- function CheckPicture(var s, Pic : string;
- var CPos : integer):word;
- procedure ReportError( kind : word); virtual;
- end;
-
- { tMoneyFormatLine }
-
- { tMoneyFormatLine is an input line intended for use }
- { real number fields associated with money. Input is }
- { preceded with a "$" sign and terminated with a "." }
- { followed by the appropriate fractional value. }
-
- pMoneyFormatLine = ^tMoneyFormatLine;
- tMoneyFormatLine = object( tFormatLine )
- constructor Init(var Bounds : tRect; AMaxlen :
- integer);
- procedure SetData(var Rec); virtual;
- procedure GetData(var Rec); virtual;
- function DataSize : word; virtual;
- end;
-
- { tPhoneFormatLine }
-
- { tPhoneFormatLine is for phone number fields. Normal }
- { 10-digit numbers are entered in the following form }
- { (###) ###-####. International numbers are entered }
- { digit after digit with spaces and hyphens where the }
- { user deems appropriate. }
-
- pPhoneFormatLine = ^tPhoneFormatLine;
- tPhoneFormatLine = object( tFormatLine )
- constructor Init(var Bounds : tRect; AMaxLen :
- integer);
- procedure SetData(var Rec); virtual;
- procedure GetData(var Rec); virtual;
- end;
-
- { tRealFormatLine }
-
- { tRealFormatLine is used for real number fields. It }
- { can handle both decimal and scientific notations. }
-
- pRealFormatLine = ^tRealFormatLine;
- tRealFormatLine = object ( tFormatLine )
- constructor Init(var Bounds : tRect; AMaxLen :
- integer);
- procedure SetData(var Rec); virtual;
- procedure GetData(var Rec); virtual;
- function DataSize : word; virtual;
- end;
-
- { tIntegerFormatLine }
-
- { tIntegerFormatLine is used for integer fields. It }
- { accepts signed integers. }
-
- pIntegerFormatLine = ^tIntegerFormatLine;
- tIntegerFormatLine = object( tFormatLine )
- constructor Init(var Bounds : tRect; AMaxLen :
- integer);
- procedure SetData(var Rec); virtual;
- procedure GetData(var Rec); virtual;
- function DataSize : word; virtual;
- end;
-
- { tNameFormatLine }
-
- { tNameFormatLine accepts words and capitalizes the }
- { first character of each word. This would be used }
- { proper names and addresses. }
-
- pNameFormatLine = ^tNameFormatLine;
- tNameFormatLine = object( tFormatLine )
- constructor Init(var Bounds : tRect; AMaxLen :
- integer);
- end;
-
- { tZipFormatLine }
-
- { tZipFormatLine is used for ZIP and Postal Code }
- { fields. It handles U.S. and Canadian format codes. }
-
- pZipFormatLine = ^tZipFormatLine;
- tZipFormatLine = object( tFormatLine )
- constructor Init(var Bounds : tRect; AMaxLen :
- integer);
- end;
-
- implementation
-
-
- { Function Copy represents a bit of syntatic sugar for }
- { the benefit of the author. It changes the Copy func. }
- { so that its parameters represent start and end points }
- { rather than a start point followed by a quantity. }
-
- function Copy(s : string; start, stop : integer) : string;
- begin
- if stop < start then Copy:=''
- else Copy:=System.Copy(s,start,stop-start+1);
- end;
-
-
-
- { Function FindMatch recursively locates the matching }
- { grouping characters for "{" and "[". }
-
- function FindMatch(P : string) : integer;
- var
- i:integer;
- match:boolean;
- c:char;
- begin
- i:=2;
- match:=false;
- while (i<=length(P)) and not match do
- begin
- if ((p[i]=']') and (p[1]='[')) or ((p[i]='}') and
- (p[1]='{')) then
- match:=true;
- if p[i]='{' then
- i:=i+FindMatch(Copy(p,i,length(p)))
- else if p[i]='[' then
- i:=i+FindMatch(Copy(p,i,length(P)))
- else inc(i);
- end;
- FindMatch:=i-1;
- end;
-
-
-
- { tFormatLine.ReportError handles errors found when the }
- { user keys inappropriate characters or presses ENTER }
- { when input is incomplete. }
-
- procedure tFormatLine.ReportError(kind:word);
- var
- w : word;
- Pic : pstring;
- begin
- Pic:=newstr(Picture);
- case kind of
- flCharError :
- begin
- sound(220);
- delay(200);
- nosound;
- end;
- flFormatError :
- begin
- w:=MessageBox('Error in Formatted Input Line'+
- ' '+
- '%s'+
- ' '+
- '(Using Paradox Picture Format)',
- @Pic,mfError+mfOkButton);
- end;
- end;
- DisposeStr(Pic);
- end;
-
-
- { tFormatLine.Valid overrides TView's Valid and reports }
- { any format errors if the user accepts the input string }
- { before the entire format requirements have been met. }
-
- function tFormatLine.Valid(command: word):boolean;
- var
- result:word;
- begin
- result:=CheckPicture(Data^,Picture,CurPos);
- if (result and flFormatOK)=0 then
- begin
- ReportError(flFormatError);
- Select;
- DrawView;
- Valid:=false;
- end
- else Valid:=true;
- end;
-
-
- { tFormatLine.CheckPicture is the function that inspects }
- { the input string passed as S against the Pic string }
- { which holds the Paradox-form Picture. If an error is }
- { found the position of the error is placed in CPos. }
-
- function tFormatLine.CheckPicture(var s, Pic : string;
- var CPos : integer) : word;
- var
- Resolved : integer;
- TempIndex : integer;
-
-
- { Function CP is the heart of tFormatLine. It }
- { determines if the string, s passed to it fits the }
- { requirements of the picture, Pic. The number of }
- { characters successful resolved is returned in the }
- { parameter resolved. When groups or repetitions are }
- { encountered CP will call itself recursively. }
-
- function CP(var s : string; Pic : string; var CPos :
- integer; var Resolved : integer) : word;
- const
- CharMatchSet = ['#','?','&','@','!'];
- var
- i : integer;
- index : integer;
- result : word;
- commit : boolean;
- Groupcount : integer;
-
- { Procedure Succeed resolves defaults and <Space> }
- { default requests }
-
- procedure Succeed;
- var
- t : integer;
- found : boolean;
- begin
- if (s[i]=' ') and (Pic[index]<>' ') and
- (Pic[index]<>',') then
- begin
- t:=index;
- found:=false;
- while (t<=length(pic)) and not found do
- begin
- if not (Pic[t] in (CharMatchSet+
- ['*','[','{',',',']','}'])) then
- begin
- if pic[t]=';' then inc(t);
- s[i]:=Pic[t];
- found:=true;
- end;
- inc(t);
- end;
- end;
- if (i>length(s)) then
- while not (Pic[index] in
- (CharMatchSet+['*','[','{',',',']','}'])) and
- (index<=length(Pic)) and
- not(Pic[index-1] in ['}',',',']']) do
- begin
- if Pic[index]=';' then inc(index);
- s[i]:=Pic[index];
- if i>length(s) then
- begin
- CPos:=i;
- s[0]:=char(i);
- end;
- inc(i);
- inc(index);
- end;
- end;
-
-
- { Function AnyLeft returns true if their are no required }
- { characters left in the Picture string. }
-
- function AnyLeft : boolean;
- var TempIndex : integer;
- begin
- TempIndex:=index;
- while ((Pic[TempIndex]='[') or (Pic[TempIndex]='*'))
- and (TempIndex<=Length(Pic)) and
- (Pic[TempIndex]<>',') do
- begin
- if Pic[TempIndex]='[' then
- Tempindex:=Tempindex+FindMatch(Copy(Pic,index,
- Length(Pic)))
- else begin
- if not (Pic[TempIndex+1] in ['0'..'9']) then
- begin
- inc(TempIndex);
- if Pic[TempIndex] in ['{','['] then
- tempIndex:=TempIndex+
- FindMatch(Copy(pic,index,length(pic)))
- else inc(TempIndex);
- end;
- end;
- end;
- AnyLeft:=(TempIndex<=length(Pic)) and
- (Pic[TempIndex]<>',');
- end;
-
-
- { Function CharMatch determines if the current character }
- { matches the corresponding character mask in the }
- { Picture string. Alters the character if necessary. }
-
- function CharMatch : word;
- var result : word;
- begin
- result:=flError;
- case Pic[index] of
- '#': if s[i] in ['0'..'9'] then result:=flCharOk;
- '?': if s[i] in ['A'..'Z','a'..'z'] then
- result:=flCharOk;
- '&': if s[i] in ['A'..'Z','a'..'z'] then
- begin
- result:=flCharOk;
- s[i]:=upcase(s[i]);
- end;
- '@': result:=flCharOk;
- '!':
- begin
- result:=flCharOk;
- s[i]:=upcase(s[i]);
- end;
- end;
- if result<>flError then commit:=true;
- CharMatch:=result;
- end;
-
- { Function Literal handles characters which are needed }
- { by the picture by otherwise used as format specifiers. }
- { All such characters are preceded by the ';' in the }
- { picture string. }
-
- function Literal : word;
- var result : word;
- begin
- inc(index);
- if s[i]=Pic[index] then result:=flCharOk
- else result:=flError;
- if result<>flError then commit:=true;
- Literal:=result;
- end;
-
-
- { Function Group handles required and optional groups }
- { in the picture string. These are designated by the }
- (* "{","}" and "[","]" character pairs. *)
-
- function Group:word;
- var
- result: word;
- TempS: string;
- TempPic: string;
- TempCPos: integer;
- PicEnd: integer;
- TempIndex: integer;
- SwapIndex:integer;
- SwapPic : string;
- begin
- TempPic:=Copy(Pic,index,length(Pic));
- PicEnd:=FindMatch(TempPic);
- TempPic:=Copy(TempPic,2,PicEnd-1);
- TempS:=Copy(s,i,length(s));
- TempCPos:=1;
-
- result:=CP(TempS,TempPic,TempCPos,TempIndex);
-
- if result=flCharOK then inc(GroupCount);
- if (result=flFormatOK) and (groupcount>0) then
- dec(GroupCount);
- if result<>flError then result:=flCharOk;
-
- SwapIndex:=index;
- index:=TempIndex;
- SwapPic:=Pic;
- Pic:=TempPic;
- if not AnyLeft then result:=flCharOk;
- pic:=SwapPic;
- index:=SwapIndex;
-
- if i>1 then s:=copy(s,1,i-1)+TempS else s:=TempS;
-
- CPos:=Cpos+TempCPos-1;
- if Pic[index]='[' then
- begin
- if result<>flError then
- i:=i+TempCPos-1
- else dec(i);
- result:=flCharOK;
- end
- else i:=i+TempCPos-1;
- index:=index+PicEnd-1;
- Group:=result;
- end;
-
-
- { Function Repetition handles repeated that may be }
- { repeated in the input string. The picture string }
- { indicates this possiblity with "*" character. }
-
- function Repetition:word;
- var
- result:word;
- count:integer;
- TempPic:string;
- TempS:string;
- TempCPos:integer;
- TempIndex:integer;
- SwapIndex:integer;
- SwapPic:string;
- PicEnd:integer;
- commit:boolean;
-
- procedure MakeCount;
- var nstr:string;
- code:integer;
- begin
- if Pic[index] in ['0'..'9'] then
- begin
- nstr:='';
- repeat
- nstr:=nstr+Pic[index];
- inc(index);
- until not(Pic[index] in ['0'..'9']);
- val(nstr,count,code);
- end
- else count:=512;
- end;
-
- procedure MakePic;
- begin
- if Pic[index] in ['{','['] then
- begin
- TempPic:=copy(Pic,index,length(Pic));
- PicEnd:=FindMatch(TempPic);
- TempPic:=Copy(TempPic,2,PicEnd-1);
- end
- else
- begin
- if Pic[index]<>';' then
- begin
- TempPic:=''+Pic[index];
- PicEnd:=3;
- if index=1 then pic:='{'+pic[index]+'}'+
- copy(pic,index+1,length(pic))
- else pic:=copy(pic,1,index-1)+
- '{'+pic[index]+'}'+
- copy(pic,index+1,length(pic));
- end
- else
- begin
- TempPic:=Pic[index]+Pic[index+1];
- PicEnd:=4;
- if index=1 then pic:='{'+pic[index]+
- pic[index+1]+'}'+
- copy(pic,index+1,length(pic))
- else pic:=copy(pic,1,index-1)+'{'+pic[index]+
- pic[index+1]+'}'+copy(pic,index+1,
- length(pic));
- end;
- end;
- end;
-
- begin
- inc(index);
- MakeCount;
- MakePic;
- result:=flCharOk;
- while (count<>0) and (result<>flError) and
- (i<=length(s)) do
- begin
- commit:=false;
- TempS:=Copy(s,i,length(s));
- TempCPos:=1;
-
- result:=CP(TempS,TempPic,TempCPos,TempIndex);
-
- if result=flCharOK then inc(GroupCount);
- if (result=flFormatOK) and
- (groupcount > 0) then dec(GroupCount);
- if result<>flError then result:=flCharOk;
-
- SwapIndex:=Index;
- Index:=TempIndex;
- SwapPic:=Pic;
- Pic:=TempPic;
- if (not AnyLeft) then result:=flCharOk;
- Pic:=SwapPic;
- index:=SwapIndex;
- if i>1 then s:=copy(s,1,i-1)+TempS else s:=TempS;
- Cpos:=Cpos+TempCpos-1;
- if (count>255) then
- begin
- if result<>flError then
- begin
- i:=i+TempCpos-1;
- if not commit then commit:=true;
- result:=flCharOk;
- end
- else dec(i);
- end
- else i:=i+TempCPos-1;
- inc(i);
- dec(count);
- end;
- dec(i);
- index:=index+PicEnd-1;
- if result=flError then
- if (count>255) and not commit
- then result:=flCharOk;
- repetition:=result;
- end;
-
- begin{ of function CP}
- i:=1;
- index:=1;
- result:=flCharOk;
- commit:=false;
- Groupcount:=0;
- while (i<=length(s)) and (result<>flError) do
- begin
- if index>length(Pic) then result:=flError else
- begin
- if s[i]=' ' then Succeed;
- if Pic[index] in CharMatchSet then
- result:=CharMatch else
- if Pic[index]=';' then
- result:=Literal else
- if (Pic[index]='{') or (Pic[index]='[') then
- result:=Group else
- if Pic[index]='*' then
- result:=Repetition else
- if Pic[index] in [',','}',']'] then
- result:=flError else
- if Pic[index]=s[i] then
- begin
- result:=flCharOk;
- commit:=true;
- end
- else result:=flError;
- if (result = flError) and not commit then
- begin
- TempIndex:=Index;
- while (TempIndex<=length(Pic)) and
- ((Pic[TempIndex]<>',') and
- (Pic[TempIndex-1]<>';')) do
- begin
- if (Pic[TempIndex]='{') or
- (Pic[TempIndex]=']')
- then Index:=FindMatch( Copy( Pic,
- TempIndex,length(Pic)))+TempIndex-1;
- inc(TempIndex);
- end;
- if Pic[TempIndex]=',' then
- begin
- if Pic[TempIndex-1]<>';' then
- begin
- result:=flCharOk;
- index:=TempIndex;
- inc(index);
- end;
- end;
- end
- else if result<>flError then
- begin
- inc(i);
- inc(index);
- Succeed;
- end;
-
- end;
- end;
- Resolved:=index;
-
- if (result=flCharOk) and
- (GroupCount=0) and
- (not AnyLeft or ((Pic[index-1]=',') and
- (Pic[index-2]<>';')))
- then result:=flFormatOk;
-
- CPos:=i-1;
- CP:=result;
- end;
-
- begin{ of function CheckPicture}
- Resolved:=1;
- CheckPicture:=CP(s,Pic,CPos,Resolved);
- end;
-
- { tFormatLine.Init simply sets up the inputline and then }
- { sets up the Picture string for use by CheckPicture. }
-
- constructor tFormatLine.Init(var Bounds: tRect;
- AMaxLen: integer; Pic : string);
- begin
- tInputLine.Init(Bounds,AMaxLen);
- Picture:=Pic;
- end;
-
- { tFormatLine.HandleEvent intercepts character key }
- { presses and handles inserting these characters into }
- { Data field. Insertion only occures if a call to }
- { tFormatLine.CheckPicture is successful else }
- { tFormatLine.ReportError is called. All other events }
- { are passed on to tInputLine.HandleEvent. }
-
- procedure TFormatLine.HandleEvent(var Event: TEvent);
- var TempData : string;
- TempCurPos : integer;
- I : integer;
- begin
- if State and sfSelected <> 0 then
- if Event.What=evKeyDown then
- if Event.CharCode in [' '..#255] then
- begin
- TempData:=Data^;
- if State and sfCursorIns<>0 then
- Delete(TempData,CurPos+1,1)
- else begin
- if SelStart<>SelEnd then
- begin
- Delete(TempData,SelStart+1
- ,SelEnd-SelStart);
- CurPos:=SelStart;
- end;
- end;
- if Length(TempData)<MaxLen then
- begin
- inc(CurPos);
- insert(Event.CharCode,TempData,CurPos);
- if CheckPicture(TempData,Picture,CurPos)=flError then
- ReportError(flCharError)
- else Data^:=TempData;
- SelStart:=0;
- SelEnd:=0;
- if FirstPos> CurPos then FirstPos:=CurPos;
- I:=CurPos-Size.X+2;
- if FirstPos<I then FirstPos:=I;
- DrawView;
- ClearEvent(Event);
- end;
- end;
- tInputLine.HandleEvent(Event);
- end;
-
-
- constructor tMoneyFormatLine.Init;
- begin
- tFormatLine.Init(Bounds,AMaxLen,'$#[#][#]*{;,###}.##');
- end;
-
- procedure tMoneyFormatLine.GetData;
- var Figure : real absolute Rec;
- TempData : string;
- i : integer;
- code : integer;
- begin
- TempData:=Data^;
- for i:=length(TempData) downto 1 do
- if TempData[i] in ['$',','] then
- Delete(TempData,i,1);
- val(TempData,Figure,code);
- if code<>0 then ReportError(flFormatError);
- end;
-
- procedure tMoneyFormatLine.SetData;
- var Figure : real absolute Rec;
- TempData : string;
- i,decimal, count : integer;
- begin
- str(Figure:0:2,TempData);
- i:=pos('.',TempData);
- count:=0;
- while (i<>1) do
- begin
- inc(count);
- dec(i);
- if count=3 then
- begin
- insert(',',TempData,i);
- count:=0;
- end;
- end;
- if TempData[1]=',' then delete(TempData,1,1);
- Data^:='$'+TempData;
- end;
-
- function tMoneyFormatLine.DataSize : word;
- begin
- DataSize:=sizeof(real);
- end;
-
- constructor tPhoneFormatLine.Init;
- begin
- tFormatLine.Init(Bounds,AMaxLen,
- '(###) ###-####,#*{#, ,-#}');
- end;
-
- procedure tPhoneFormatLine.GetData;
- var i : integer;
- Default : string absolute Rec;
- begin
- for i:=length(Data^) downto 1 do
- if Data^[i] in [' ','-','(',')'] then Delete(Data^,i,1);
- Default:=Data^;
- end;
-
- procedure tPhoneFormatLine.SetData;
- var i:integer;
- Default : string absolute Rec;
- begin
- if length(Default)=10 then
- Default:='('+Copy(Default,1,3)+') '+Copy(Default,4,6)+
- '-'+Copy(Default,7,10);
- Data^:=Default;
- end;
-
- constructor tRealFormatLine.Init;
- begin
- tFormatLine.Init(Bounds, AMaxLen,
- '[+,-]#*#[[.*#][{E,e}[+,-]#[#][#][#]]]');
- end;
-
- procedure tRealFormatLine.GetData;
- var Result : real absolute Rec;
- code : integer;
- begin
- val(Data^, Result, code);
- if code<>0 then ReportError(flFormatError);
- end;
-
- procedure tRealFormatLine.SetData;
- var Default : real absolute Rec;
- begin
- if Default>1E6 then
- str(Default,Data^)
- else str(Default:0:8,Data^);
- end;
-
- function tRealFormatLine.DataSize : word;
- begin
- DataSize:=sizeof(Real);
- end;
-
- constructor tIntegerFormatLine.Init;
- begin
- tFormatLine.Init(Bounds,AMaxLen,'[+,-]#*#');
- end;
-
- procedure tIntegerFormatLine.SetData;
- var Default : integer absolute Rec;
- begin
- str(Default,Data^);
- end;
-
- procedure tIntegerFormatLine.GetData;
- var Result : integer absolute Rec;
- code : integer;
- begin
- val(Data^,Result,code);
- if code<>0 then ReportError(flFormatError);
- end;
-
- function tIntegerFormatLine.DataSize : word;
- begin
- DataSize:=sizeof(integer);
- end;
-
- constructor tNameFormatLine.Init;
- begin
- tFormatLine.Init(Bounds,AMaxLen,'*[![*?][@][ ]]');
- end;
-
- constructor tZipFormatLine.Init;
- begin
- tFormatLine.Init(Bounds,AMaxLen,'#####[-####],& #');
- end;
-
- end.
-